home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-25 | 13.2 KB | 432 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: FWLnkDst.cpp
- // Release Version: $ ODF 1 $
- //
- // Copyright: (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #include "FWFrameW.hpp"
-
- #ifndef FWLNKDST_H
- #include "FWLnkDst.h"
- #endif
-
- // ----- Framework Includes -----
-
- #ifndef FWPART_H
- #include "FWPart.h"
- #endif
-
- #ifndef FWPRESEN_H
- #include "FWPresen.h"
- #endif
-
- #ifndef FWLNKITE_H
- #include "FWLnkIte.h"
- #endif
-
- #ifndef FWCLNINF_H
- #include "FWClnInf.h"
- #endif
-
- #ifndef FWINTER_H
- #include "FWInter.h"
- #endif
-
- // ----- Foundation Includes -----
-
- #ifndef FWPRIDEB_H
- #include "FWPriDeb.h"
- #endif
-
- #ifndef FWBARRAY_H
- #include "FWBArray.h"
- #endif
-
- // ----- OpenDoc Includes -----
-
- #ifndef SOM_Module_OpenDoc_StdProps_defined
- #include <StdProps.xh>
- #endif
-
- #ifndef SOM_Module_OpenDoc_StdTypes_defined
- #include <StdTypes.xh>
- #endif
-
- #ifndef SOM_ODStorageUnit_xh
- #include <StorageU.xh>
- #endif
-
- #ifndef SOM_ODSession_xh
- #include <ODSessn.xh>
- #endif
-
- #ifndef SOM_ODLink_xh
- #include <Link.xh>
- #endif
-
- //========================================================================================
- // Runtime information
- //========================================================================================
-
- #ifdef FW_BUILD_MAC
- #pragma segment odflinking
- #endif
-
- //========================================================================================
- // Template Instantiations
- //========================================================================================
-
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollectionIterator, FW_CLinkDestination)
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollection, FW_CLinkDestination)
-
- #ifdef FW_USE_TEMPLATE_PRAGMAS
-
- #pragma template_access public
- #pragma template FW_TOrderedCollection<FW_CLinkDestination>
- #pragma template FW_TOrderedCollectionIterator<FW_CLinkDestination>
-
- #endif
-
- //========================================================================================
- // class FW_CLinkDestination
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::FW_CLinkDestination
- //----------------------------------------------------------------------------------------
-
- FW_CLinkDestination::FW_CLinkDestination(Environment* ev,
- ODLink* odLink,
- ODLinkInfo* linkInfo,
- FW_CPresentation* presentation)
- : FW_CLink(ev, presentation),
- fODLink(NULL),
- fRegistered(FALSE),
- fPart(NULL),
- fEstablished(false),
- fEmbed(FALSE),
- fDataInterchange(presentation->GetPart(ev)->GetDataInterchange(ev))
- {
- if (odLink)
- {
- fODLink = odLink;
- odLink->Acquire(ev);
- }
-
- // Copy link info
- fLinkInfo = *linkInfo;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::~FW_CLinkDestination
- //----------------------------------------------------------------------------------------
-
- FW_CLinkDestination::~FW_CLinkDestination()
- {
- FW_SOMEnvironment ev;
- this->Unregister(ev);
- if (fODLink)
- fODLink->Release(ev);
-
- if (fEmbed) // fEmbedInfo is valid
- {
- //-- Dispose OpenDoc strings
- if (fEmbedInfo.selectedKind != kODNULL)
- ODDisposePtr(fEmbedInfo.selectedKind);
- if (fEmbedInfo.translateKind != kODNULL)
- ODDisposePtr(fEmbedInfo.translateKind);
- if (fEmbedInfo.editor != kODNULL)
- ODDisposePtr(fEmbedInfo.editor);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::PrivEstablishLink
- //----------------------------------------------------------------------------------------
-
- void FW_CLinkDestination::PrivEstablishLink(Environment* ev)
- {
- this->LinkEstablished(ev);
- fEstablished = true;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::LinkEstablished
- //---------------------------------------------------------------------------------------
- void FW_CLinkDestination::LinkEstablished(Environment* ev)
- {
- FW_UNUSED(ev);
- // Override to change the status of embedded frames to kODInLinkDestination
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::LinkUpdated
- //----------------------------------------------------------------------------------------
-
- void FW_CLinkDestination::LinkUpdated(Environment* ev, ODUpdateID id)
- {
- ODLinkKey linkKey;
- if (!fODLink->Lock(ev, 0, &linkKey))
- return;
-
- /* The following Try-block is for when OpenDoc throws an exception in GetContentStorageUnit.
- If a cross-document link was just created, LinkUpdated gets called before the link content SU
- has received any data. In that case we want to just let the exception fall on the floor.
- LinkUpdated will be called again after the link data has been written.
- */
- ODStorageUnit* su;
- FW_VOLATILE(linkKey);
- FW_TRY
- {
- su = fODLink->GetContentStorageUnit(ev, linkKey); /* cross-doc link will fail the 1st time */
- }
- FW_CATCH_BEGIN
- FW_CATCH_REFERENCE(FW_XException, ex)
- {
- fODLink->Unlock(ev, linkKey);
- // If GetContentStorageUnit returned the error kODErrNoLinkContent,
- // the last source update failed; don't update the link at this time.
- if (ex.GetPlatformError() == kODErrNoLinkContent)
- return;
- FW_THROW_SAME();
- }
- FW_CATCH_END
-
- FW_Boolean updateSuccessful = false;
- FW_TRY
- {
- if (this->DoUpdateLink(ev, su, fEmbed ? &fEmbedInfo : NULL)) // part-specific
- {
- // --- Update the link info ---
- fLinkInfo.change = id;
- fLinkInfo.changeTime = fODLink->GetChangeTime(ev);
- updateSuccessful = true;
- }
- else // Couldn't update the link, for some reason
- if (!fEstablished)
- FW_THROW(FW_XException(kODErrCannotEstablishLink));
- }
- FW_CATCH_BEGIN
- FW_CATCH_EVERYTHING()
- {
- // error occurred in DoUpdateLink somewhere
- fODLink->Unlock(ev, linkKey);
- FW_THROW_SAME();
- }
- FW_CATCH_END
-
- // --- We're done with the link content SU ---
- fODLink->Unlock(ev, linkKey);
-
- if (!fEstablished) // first update must have failed
- this->PrivEstablishLink(ev);
-
- // --- Propagate changes to source links maintained by the part ---
- if (updateSuccessful)
- this->DoPropagateChanges(ev, id);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::DoPropagateChanges
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::DoPropagateChanges(Environment* ev, ODUpdateID updateID)
- {
- // Content in the specified destination link has changed.
- // Override to propagate changes to source links maintained by this part (part-specific)
-
- // --- Notify all containing parts of the change ---
- fPresentation->ContentUpdated(ev, updateID);
-
- fPresentation->Invalidate(ev); // force all frames to be redrawn
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::Register
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::Register(Environment* ev, FW_CPart* itsPart)
- {
- ODUpdateID linkUpdateID = fODLink->GetUpdateID(ev);
- FW_Boolean needsUpdate = (fLinkInfo.change != linkUpdateID);
-
- if (fLinkInfo.autoUpdate)
- {
- //--- Register for automatic updates ---
- // First determine if another link with the same ODLink as ours already registered
- FW_Boolean alreadyRegistered = FALSE;
- FW_CPartLinkDestIterator iter(itsPart);
- for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
- {
- if ((link != this) && fODLink->IsEqualTo(ev, link->GetODLink(ev))
- && link->IsRegistered(ev))
- {
- alreadyRegistered = TRUE;
- break;
- }
- }
- if (!alreadyRegistered)
- {
- fODLink->RegisterDependent(ev, itsPart->GetODPart(ev), fLinkInfo.change);
- // part::LinkUpdated call will be generated
- needsUpdate = FALSE;
- }
- fRegistered = TRUE;
- itsPart->GetODPart(ev)->Acquire(ev);
- fPart = itsPart; // remember which part we're registered to, so we can Unregister
- }
-
- if (needsUpdate) // Manually update now
- this->LinkUpdated(ev, linkUpdateID);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::Unregister
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::Unregister(Environment* ev)
- {
- if (!fRegistered) return;
-
- if (fLinkInfo.autoUpdate)
- {
- // Unregister, if this is the last automatically updated destination of the link in the part
- FW_ASSERT(fPart);
- short autoCount = 0;
- FW_CPartLinkDestIterator iter(fPart);
- for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
- {
- if (link->IsAutoUpdate(ev) && fODLink->IsEqualTo(ev, link->GetODLink(ev)))
- autoCount++;
- }
- if (autoCount == 1) // this is the only registered link
- {
- fODLink->UnregisterDependent(ev, fPart->GetODPart(ev));
- }
- }
-
- if (fPart)
- {
- fPart->GetODPart(ev)->Release(ev);
- fPart = NULL;
- }
-
- fRegistered = FALSE;
- }
-
- //---------------------------------------------------------------------------------------
- // FW_CLinkDestination::BreakLink
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::BreakLink(Environment* ev)
- {
- this->Unregister(ev);
- fEstablished = false;
- }
-
- //---------------------------------------------------------------------------------------
- // FW_CLinkDestination::RestoreLink
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::RestoreLink(Environment* ev, FW_CPart* part)
- {
- fLinkInfo.change = kODUnknownUpdate;
-
- // Re-register the link if necessary
- this->Register(ev, part);
- }
-
- //---------------------------------------------------------------------------------------
- // FW_CLinkDestination::ExternalizeLink
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::ExternalizeLink(Environment* ev, ODStorageUnit* storageUnit,
- FW_CCloneInfo* cloneInfo)
- {
- //-- Storage unit must be focused to property kODPropContents, value destLinkFormat
- ODStorageUnitRef suRef;
- fODLink->Externalize(ev);
-
- ODID linkID = fODLink->GetID(ev);
- if (cloneInfo != NULL)
- {
- linkID = cloneInfo->Clone(ev, linkID, 0, 0);
- }
-
- // May not have been able to clone the link
- if (linkID == kODNULL) return;
-
- //--- Write the link version number ---
- long version = FW_kLinkVersionNumber;
- FW_CByteArray byteArray(&version, sizeof(long));
- storageUnit->SetValue(ev, byteArray);
-
- //--- Write a reference to the link ---
- storageUnit->GetStrongStorageUnitRef(ev, linkID, suRef);
- byteArray.Set(&suRef, sizeof(ODStorageUnitRef));
- storageUnit->SetValue(ev, byteArray);
-
- //--- Write link info ---
- ODType savedKind = fLinkInfo.kind; // save kind string
- fLinkInfo.kind = (ODType) strlen(savedKind) + 1;
- byteArray.Set(&fLinkInfo, sizeof(ODLinkInfo));
- storageUnit->SetValue(ev, byteArray); // write out linkinfo
- byteArray.Set((void*)savedKind, (ODULong)fLinkInfo.kind);
- storageUnit->SetValue(ev, byteArray); // write out kind string
- fLinkInfo.kind = savedKind; // restore kind string
-
- //--- Write embed info, if any ---
- byteArray.Set(&fEmbed, sizeof(FW_Boolean));
- storageUnit->SetValue(ev, byteArray);
- if (fEmbed)
- {
- //-- save strings, except for selectedKind, which was written above
- savedKind = fEmbedInfo.translateKind; // save translateKind string
- if (savedKind != NULL)
- fEmbedInfo.translateKind = (ODType) strlen(savedKind) + 1;
- ODEditor savedEditor = fEmbedInfo.editor; // save editor string
- if (savedEditor != NULL)
- fEmbedInfo.editor = (ODType) strlen(savedEditor) + 1;
-
- //-- write fields of fEmbedInfo
- byteArray.Set(&fEmbedInfo, sizeof(ODPasteAsResult));
- storageUnit->SetValue(ev, byteArray);
- if (savedKind != NULL) // write the translateKind string
- {
- byteArray.Set((void*)savedKind, (ODULong)fEmbedInfo.translateKind);
- storageUnit->SetValue(ev, byteArray);
- }
- if (savedEditor != NULL) // write the editor string
- {
- byteArray.Set((void*)savedEditor, (ODULong)fEmbedInfo.editor);
- storageUnit->SetValue(ev, byteArray);
- }
-
- //-- Restore string ptrs to fEmbedInfo
- fEmbedInfo.translateKind = savedKind;
- fEmbedInfo.editor = savedEditor;
- }
-
- //--- Write out data specific to this part's link ---
- this->DoExternalizeLink(ev, storageUnit, cloneInfo);
- }
-
- //---------------------------------------------------------------------------------------
- // FW_CLinkDestination::SavePasteAsSettings
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::SavePasteAsSettings(Environment* ev, ODPasteAsResult& pasteAsResult)
- {
- FW_UNUSED(ev);
- // Record the PasteAs dialog settings, so links can be updated appropriately
- fLinkInfo.kind = pasteAsResult.selectedKind; // Copy the pointer
- fEmbed = (pasteAsResult.mergeSetting == kODFalse);
- if (fEmbed)
- {
- // Embed As: remember the user's settings
- fEmbedInfo = pasteAsResult;
- // Set pointer fields to NULL so they won't be disposed by the caller
- pasteAsResult.translateKind = NULL;
- pasteAsResult.editor = NULL;
- }
-
- pasteAsResult.selectedKind = NULL; // so caller doesn't dispose it
- }
-
-